﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FParser.Parser;
using FParser.Parser.Expressions;

namespace FParser.Visualization
{
    public class DotExporter
    {
        List<Expression> m_Expressions;

        public DotExporter(List<Expression> exps)
        {
            this.m_Expressions = exps;
        }

        public string Export()
        {
            string ret = i_Export(this.m_Expressions, "Root");
            return "digraph { " + ret + " } ";
        }

        int weight = 8;

        private string i_Export(List<Expression> exps, string rootNode)
        {
            string output = "";
            string oldObj = rootNode;
            foreach (Expression exp in exps)
            {
                if (exp.type != EnumExpressionType.SEMICOLON)
                {
                    weight+=10;
                    string nextObj = getNextObject();
                    output += oldObj + " -> " + nextObj + " [ weight= "+weight.ToString() +" shape=triangle ]\n";
                    output += i_ExportExpression(exp, nextObj) + "\n";

                    oldObj = nextObj;
                }
            }

            return output;
        }

        int expCount = 0;
        private string getNextObject()
        {
            expCount++;
            return "object" + expCount.ToString();
        }
        private string getLastObject()
        {
            return "object" + expCount.ToString();
        }
        private string i_ExportExpression(Expression exp, string obj)
        {
            string output = "";

            switch (exp.type)
            {
                case EnumExpressionType.ASSIGNMENT:
                    string leftObj = getNextObject();
                    string rightObj = getNextObject();
                    output += obj + " [label = \"=\" shape=box] \n";
                    output += obj + " -> " + leftObj + " \n";
                    output += obj + " -> " + rightObj + " \n";
                    output += i_ExportExpression(exp.left, leftObj) + "\n";
                    output += i_ExportExpression(exp.right, rightObj) + "\n";
                    break;
            
                case EnumExpressionType.TYPE:
                    output += dotApi_nodeLabel(obj, "$" + exp.data);
                    break;
                
                case EnumExpressionType.CALL:
                    CallExpression call = (CallExpression)exp;
                    output += dotApi_nodeLabel(obj, call.Method + "()");
                    break;

                case EnumExpressionType.METHOD:
                    MethodExpression mexp = (MethodExpression)exp;
                    output += dotApi_nodeLabel(obj, "function " + mexp.MethodName);
                    output += obj + "->" + i_Export(mexp.Content, getNextObject());
                    break;

                case EnumExpressionType.STATIC_DATA:
                    output += dotApi_nodeLabel(obj, exp.data );
                    break;

                case EnumExpressionType.IF:
                    IfExpression ifexp = (IfExpression)exp;
                    output += dotApi_nodeLabel(obj, "if");
                    output += obj + " -> " + i_Export(ifexp.Content, getNextObject());

                    if (ifexp.HasElse)
                    {
                        output += obj + " -> " + i_Export(ifexp.ElseContent, getNextObject());
                    }
                    break;

                case EnumExpressionType.SEMICOLON:
                    output += dotApi_nodeLabel(obj, "Next Step");
                    break;

                case EnumExpressionType.WHILE:
                    WhileExpression whileExp = (WhileExpression) exp;
                    string operation = getNextObject();
                    output += dotApi_nodeLabel(obj, "while");
                    output += obj + " -> " + i_Export(whileExp.Content, getNextObject()) + "\n";
                    break;

                case EnumExpressionType.OPERATION:
                    OperationExpression opExp = (OperationExpression) exp;
                    leftObj = getNextObject();
                    rightObj = getNextObject();
                    output += obj + " [label = \""+((char)opExp.OpType).ToString()+"\"] \n";
                    output += obj + " -> " + leftObj + " \n";
                    output += obj + " -> " + rightObj + " \n";
                    output += i_ExportExpression(exp.left, leftObj) + "\n";
                    output += i_ExportExpression(exp.right, rightObj) + "\n";
                    break;

                default:
                    output += "undef";
                    break;

                
            }


            return output;
        }

        private string dotApi_nodeLabel(string node, string label)
        {
            return node + " [label=\"" + label + "\"] \n";
        }


    }
}
